import { ProxyOb } from "./ProxyOb";
import VmBase from "./VmBase";

/*
 * @features: 父节点
 * @description: 说明
 * @Date: 2021-09-07 22:16:09
 * @Author: judu233(769471424@qq.com)
 * @LastEditTime: 2021-09-11 16:16:02
 * @LastEditors: judu233
 */
const { ccclass, property, executionOrder } = cc._decorator;

@ccclass
@executionOrder(-1)
export default class VmParent extends cc.Component {

    @property({ displayName: `深遍历`, tooltip: `会遍历该节点的所有子节点, 并且过滤掉VmParent组件`, })
    isDeep = false;

    /**绑定的标签，可以通过这个tag 获取 当前的 vm 实例 */
    tag: string = '_temp';

    /**需要绑定的私有数据 */
    data: any = {};

    /**代理者 */
    proxyOb: ProxyOb<any>;

    /**观察的子节点vmBase组件 */
    vmBaseCom: VmBase[] = [];

    onLoad() {
        this.onBind();
    }

    onDestroy() {
        this.onUnBind();
    }

    /**在 onLoad 完成 和 start() 之前调用，你可以在这里进行初始化数据等操作 */
    onBind() {
        //创建代理
        this.tag = `_temp<${this.node.uuid.replace('.', '')}>`;
        this.proxyOb = new ProxyOb(this.data, this.tag, 'DataProxy_', true);
        this.data = this.proxyOb.proxy;

        //搜寻所有节点：找到 watch path 替换观察路径
        let comps = this.getVMComponents();
        comps.forEach(com => this.replaceVMPath(com, this.tag));
    }

    /**在 onDestroy() 后调用,此时仍然可以获取绑定的 data 数据*/
    onUnBind() {
        /**解除全部引用 */
        this.data = this.proxyOb.target;
        ProxyOb.remove(this.tag);
    }

    /**替换字节点的观察路径 */
    private replaceVMPath(comp: VmBase, tag: string) {
        //let comp_name: string = comp.name;
        if (comp.useMultipathMode) {
            let pathArr = comp.watchPathArr;
            if (pathArr) {
                for (let i = 0; i < pathArr.length; i++) {
                    const path = pathArr[i];
                    pathArr[i] = path.replace('*', tag);
                }
            }
        } else {
            //VMLabel 遇到特殊 path 就优先替换路径
            let path = comp.watchPath;
            if (path.split('.')[0] === '*') {
                comp.watchPath = path.replace('*', tag);
            }
        }
    }

    /**获取该节点下的VM 组件 */
    private getVMComponents() {
        let findList = [];
        let findCom = (findNode: cc.Node) => {
            for (let node of findNode.children) {
                let coms = node.getComponent(VmBase)
                coms && findList.push(coms);
                if (this.isDeep) {
                    findCom(node);
                }
            }
        }
        findCom(this.node);
        return findList;
    }
}
